package com.example.devecohp;

import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Splitter;
import com.intellij.psi.PsiFile;
import com.intellij.ui.components.JBScrollPane;

import javax.swing.*;
import javax.swing.tree.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * this class control the toolwindow of this plugin
 */
public class ToolWindowInfo {
    public final JLabel defectsLabel;
    public final JLabel errorsLabel;
    public final JLabel warnsLabel;
    public final JLabel infosLabel;
    public final JTextField filterTextField;
    public final Splitter secondarySplitter;
    public final JComboBox<String> languageOption;
    public final JCheckBox includeError;
    public final JCheckBox includeWarning;
    public final JCheckBox includeInfo;

    public final JBScrollPane scrollPane;
    public final JTree container;

    public final DefaultMutableTreeNode root;
    public final Project project;

    /**
     * @param project the project this is for
     */

    public ToolWindowInfo(Project project){
        this.project=project;
        this.defectsLabel=new JLabel("Defects");
        this.errorsLabel=new JLabel("Errors");
        this.infosLabel=new JLabel("Infos");
        this.warnsLabel=new JLabel("Warns");
        this.filterTextField=new JTextField("filter by description, ruleId", 20);
        this.secondarySplitter=new Splitter();
        this.languageOption =new JComboBox<>();

        this.root=new DefaultMutableTreeNode("");
        this.container=new JTree(root);

        this.scrollPane = new JBScrollPane(this.container);
        this.container.setRootVisible(false);
        this.container.setShowsRootHandles(true);

        this.container.addTreeSelectionListener(e -> {
            if(e.getNewLeadSelectionPath()==null){
                return;
            }
            Object[] treePath = e.getNewLeadSelectionPath().getPath();
            if(treePath.length==3){
                String ruleString = treePath[2].toString();
                Pattern parenthesesPattern = Pattern.compile("\\((.*?)\\)");
                Matcher parenthesesMatcher = parenthesesPattern.matcher(ruleString);
                String wordsInParentheses;

                if (parenthesesMatcher.find()) {
                    wordsInParentheses = parenthesesMatcher.group(1);

                    if (parenthesesMatcher.find()) {

                        wordsInParentheses=parenthesesMatcher.group(1);

                    }
                    String language = DocumentManager.CHINESE;
                    if(this.languageOption.getSelectedItem()!=null){
                        language=this.languageOption.getSelectedItem().toString();
                    }
                    Auditor.updateDocumentPanel(this, wordsInParentheses, language);
                }

            }

        });
        this.container.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent evt) {
                JTree tree = (JTree) evt.getSource();
                if (evt.getClickCount() == 2) {
                    TreePath path = tree.getPathForLocation(evt.getX(), evt.getY());
                    if(path==null){
                        return;
                    }
                    Object[] treePath = path.getPath();
                    if(treePath.length==3){
                        String filePath = getPathFromTitle(treePath[1].toString());
                        String ruleString = treePath[2].toString();
                        PageInfo pageInfo = PageManager.getInstance(project).getPageInfo(filePath);
                         if(pageInfo!=null){
                         PsiFile psiFile = pageInfo.oldFile;
                             try {
                                 Auditor.jump(ruleString, project,psiFile.getVirtualFile().getPath());
                             } catch (IOException e) {
                                 throw new RuntimeException(e);
                             }

                         }
                    }

                }
            }
        });
        DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) this.container.getCellRenderer();
        renderer.setLeafIcon(null);
        renderer.setClosedIcon(null);
        renderer.setOpenIcon(null);
        this.includeInfo =new JCheckBox();
        this.includeWarning =new JCheckBox();
        this.includeError =new JCheckBox();


    }

    /**
     * add a page to the ui
     * @param pageInfo the pageInfo for the page
     */
    public void addNodeForPage(PageInfo pageInfo){
        DefaultMutableTreeNode defaultMutableTreeNode= createPageNode(pageInfo);
        updateTreeElement(pageInfo.getAuditEntries(),defaultMutableTreeNode);
        this.root.add(defaultMutableTreeNode);
        ((DefaultTreeModel)this.container.getModel()).nodeStructureChanged(this.root);
        reloadTree();
    }

    /**
     * expand all path of the container
     */
    public void expandAll(){
        for(int i=0;i<this.container.getRowCount();i++){
            this.container.expandRow(i);
        }
    }

    /**
     * update the container according to the user input text
     * @param inputs the user input text
     * @param parent the node representing the file
     */

    public void updateTreeElement(List<String> inputs, DefaultMutableTreeNode parent){
        MyToolWindowFactory.sortAuditList(inputs);
        parent.removeAllChildren();
        for(String s:inputs){
            DefaultMutableTreeNode rule=new DefaultMutableTreeNode(s);
            parent.add(rule);
        }
    }



    /**
     * reload a node to update ui
     * @param node the node to reload
     */
    public void reloadTree(TreeNode node){
        DefaultTreeModel model = (DefaultTreeModel)this.container.getModel();
        model.nodeChanged(node);
    }

    /**
     * reload the whole tree to update ui
     */
    public void reloadTree(){
        int count = this.root.getChildCount();
        for (int i = 0; i < count; i++) {
            reloadTree(this.root.getChildAt(i));
        }
    }

    /**
     * filter the rules in the input PageInfo list according to the user input text and update the ui
     * @param userInput the user input text
     * @param pageInfos the PageInfos to include
     */
    public void filterAllRules(String userInput, List<PageInfo> pageInfos){
        boolean includeError = this.includeError.isSelected();
        boolean includeWarning=this.includeWarning.isSelected();
        boolean includeInfo=this.includeInfo.isSelected();
        Object[] selectedPath = new String[]{"","",""};
        TreePath p = this.container.getSelectionPath();
        if(p!=null) {
            Object p0 = p.getPath()[0];
            if(p0 instanceof TreePath){
                selectedPath = ((TreePath)p0).getPath();
            }else{
                selectedPath=p.getPath();
            }
        }
        String selectedFile = getPathFromTitle(selectedPath[1].toString());
        String selectedRule = selectedPath[2].toString();
        this.root.removeAllChildren();
        Iterator<PageInfo> iterator = pageInfos.iterator();
        DefaultMutableTreeNode selected = null;
        while (iterator.hasNext()){
            PageInfo pageInfo = iterator.next();
             if(pageInfo!=null) {
                 List<String> auditlist = pageInfo.getAuditEntries(includeError,includeWarning,includeInfo);
                MyToolWindowFactory.sortAuditList(auditlist);
                 DefaultMutableTreeNode t = createPageNode(pageInfo);;
                 Iterator var1 = auditlist.iterator();
                 while(var1.hasNext()) {
                     String entry = (String)var1.next();
                     if (entry.toLowerCase().contains(userInput.toLowerCase()) || userInput.isEmpty() || userInput.equals("filter by description, ruleId")) {
                         DefaultMutableTreeNode rule=new DefaultMutableTreeNode(entry);
                         t.add(rule);
                         if(entry.equals(selectedRule)&& getPathFromTitle(t.toString()).equals(selectedFile)){
                             selected = rule;
                         }
                     }
                 }
                 if(t.getChildCount()>0){
                     this.root.add(t);
                 }
             }
        }
        ((DefaultTreeModel)this.container.getModel()).nodeStructureChanged(this.root);
        expandAll();

        reloadTree(this.root);
        if(selected!=null){
            this.container.setSelectionPath(new TreePath(selected.getPath()));

        }
    }

    /**
     * Create a tree node for a file
     * @param pageInfo the pageInfo object for the file
     * @return the tree node created
     */
    public DefaultMutableTreeNode createPageNode(PageInfo pageInfo){
        String title = pageInfo.getFileName() + " : " + pageInfo.oldFile.getVirtualFile().getPath() + " " + pageInfo.getDefects();
        return new DefaultMutableTreeNode(title);
    }

    /**
     * convert the string appear on a node for a file to the path of the file
     * @param title the string appear on a node
     * @return the path of the file
     */
    public String getPathFromTitle(String title){
        Pattern pattern = Pattern.compile(" : (.*) \\d+$");
        Matcher pathMatcher = pattern.matcher(title);
        if(pathMatcher.find()){
            String result = pathMatcher.group(1);
            return result;
        }
        return "";
    }

    /**
     * reset the includeError, includeInfo, includeWarning to match the information stored in pageInfo, update ui
     * if needed
     * @param pageInfo the page information to match
     */

    public void reset(PageInfo pageInfo){
        if(this.includeError.isSelected()!=pageInfo.showErrors) {
            this.includeError.doClick();
        }
        if(this.includeInfo.isSelected()!=pageInfo.showInfo){
            this.includeInfo.doClick();
        }
        if(this.includeWarning.isSelected()!=pageInfo.showWarnings) {
            this.includeWarning.doClick();
        }
    }

    /**
     * remove all the visible files and rules from the ui
     */
    public void clear(){
        this.root.removeAllChildren();
    }


}